﻿/*
** Haaf's Game Engine 1.5
** Copyright (C) 2003-2004, Relish Games
** hge.relishgames.com
**
** hgeFont helper class header
*/


module core.hgefont;


private import core.hgeall;

private import std.string;
private import std.cstream;
private import std.stdio;
private import std.regexp;
private import std.windows.charset;
private import std.utf;

const MAX_PATH          	=260;
const HGETEXT_LEFT			=0;
const HGETEXT_RIGHT		=1;
const HGETEXT_CENTER		=2;
const HGETEXT_HORZMASK		=0x03;

const HGETEXT_TOP			=0;
const HGETEXT_BOTTOM		=4;
const HGETEXT_MIDDLE		=8;
const HGETEXT_VERTMASK		=0x0C;


const char[] FNTHEADERTAG	="[HGEFONT]";
const char[] FNTBITMAPTAG	="Bitmap";
const char[] FNTCHARTAG	="Char";

/*
** HGE Font class
*/
class hgeFont
{

	this(char[] fileName)
	{	int		x, y, w, h, a, c;

		FILE* 		f ;
		CFile    	file ;
		char[]		fontImg;
		gameInfo gi=gameInfo.getInstance();
		
		hge = gameInfo.hge();

		fHeight=0.0f;
		fScale=1.0f;
		fRot=0.0f;
		fTracking=0.0f;
		fSpacing=1.0f;
		hTexture=0;

		fZ=0.5f;
		nBlend=BLEND_COLORMUL | BLEND_ALPHABLEND | BLEND_NOZWRITE;
		dwCol=0xFFFFFFFF;


		f	= fopen(toStringz(fileName),"r");
			if(!f)throw new Exception("	*打开字体文件失败	名称=	"~fileName);
		file = new CFile(f,std.cstream.FileMode.In,true);

		file.position = 0;

		auto reg_fntName = RegExp( "Bitmap=(.+)" );
		auto mr = RegExp( "Char=\"(.)\",([0-9]+),([0-9]+),([0-9]+),([0-9]+),([0-9]+),([0-9]+)" );

		enum  fntStata	{	fntHead_ok, 	fntBmp_ok,	fntChar_ok, fnt_null	}
		fntStata	fns=  fntStata.fnt_null;		//当前进行状态
			foreach(ulong i,char[] line; file) 
			{	int k;

				switch(fns){

				case fntStata.fnt_null: 				//第一次进入
					if(line == FNTHEADERTAG)	fns = fntStata.fntHead_ok; 
					else{ hge.System_Log("Font %.*s has incorrect format.", fileName);
							file.close();
							throw new Exception("		*载入字体文件出错!  错误的文件格式!");
						}

					break;

				case fntStata.fntHead_ok:			//已证明是 [HGEFONT]
					if(reg_fntName.test(line)){
						fontImg		= reg_fntName.replace("$1");
						//ftex= Texture(fontImg);
						hTexture	= gi.res.tex_load(fontImg);

						fns	=	fntStata.fntBmp_ok;
					}
					break;
				case fntStata.fntBmp_ok:				//已证明是 "Bitmap"

					if (mr.test( line ) ){
					k =	mr.replace("$1")[0];
					x =	atoi( mr.replace("$2") );
					y = atoi( mr.replace("$3") );
					w =	atoi( mr.replace("$4") );
					h = atoi( mr.replace("$5") );
					a = atoi( mr.replace("$6") );
					c = atoi( mr.replace("$7") );
					//mes(k,",",x,",", y,",",w,",",h);

					letters[k] = new hgeSprite(hTexture, cast(float)x, cast(float)y, cast(float)w, cast(float)h);
					pre[k]=cast(float)a;
					post[k]=cast(float)c;
					if(h>fHeight) fHeight=cast(float)h;

					}
					break;
					
				default:	break;
				}
			}

		file.close();
	}


	this(hgeFont fnt)
	{
		int i;

		hge = gameInfo.hge();

		hTexture	=fnt.hTexture;
		fHeight		=fnt.fHeight;
		fScale		=fnt.fScale;
		fRot		=fnt.fRot;
		fTracking	=fnt.fTracking;
		fSpacing	=fnt.fSpacing;
		dwCol		=fnt.dwCol;
		fZ			=fnt.fZ;
		nBlend		=fnt.nBlend;

		for(i=0; i<256; i++)
		{
			if(fnt.letters[i]) letters[i]=new hgeSprite(fnt.letters[i]);
			else letters[i]=null;
			pre[i]=fnt.pre[i];
			post[i]=fnt.post[i];
		}
	}


	

	~this()
	{
		for(int i=0; i<256; i++)
			if(letters[i]) delete letters[i];
	}

	

	hgeFont opAddAssign(hgeFont fnt)
	{
		int i;
		
		if(this!=fnt)
		{
			hTexture	=fnt.hTexture;
			fHeight		=fnt.fHeight;
			fScale		=fnt.fScale;
			fRot		=fnt.fRot;
			fTracking	=fnt.fTracking;
			fSpacing	=fnt.fSpacing;
			dwCol		=fnt.dwCol;
			fZ			=fnt.fZ;
			nBlend		=fnt.nBlend;

			for(i=0; i<256; i++)
			{
				if(letters[i]) delete letters[i];
				if(fnt.letters[i]) letters[i]=new hgeSprite(fnt.letters[i]);
				else letters[i]=null;
				pre[i]=fnt.pre[i];
				post[i]=fnt.post[i];
			}
		}

		return this;
	}
	


	void 	Render(float x, float y, int fontAlign, char[] string)
	{
		
		float	fx=x;

 		fontAlign 	&= HGETEXT_HORZMASK;
		if(fontAlign==HGETEXT_RIGHT) fx-=GetStringWidth(string);
		if(fontAlign==HGETEXT_CENTER) fx-=cast(int)(GetStringWidth(string)/2.0f); 

		foreach(i; string)
		{
			if(i=='\n')
			{
				y+=cast(int)(fHeight*fScale*fSpacing);
				fx=x;
				if(fontAlign==HGETEXT_RIGHT) fx-=GetStringWidth(string);
				if(fontAlign==HGETEXT_CENTER) fx-=cast(int)(GetStringWidth(string)/2.0f);
			}
			else
			{
				if(!letters[i]) i='?';
				if(letters[i])
				{
					fx+=pre[i]*fScale;
					letters[i].RenderEx(fx, y, fRot, fScale);
					fx+=(letters[i].GetWidth()+post[i]+fTracking)*fScale;
				}
			}
		}
	}


	void printf(float x, float y, int fontAlign, ...)
	{	char[] line;
	
		void putc(dchar c){
			std.utf.encode(line, c);
		}
		std.format.doFormat(&putc, _arguments, _argptr);
		//mes(line[]);
		Render(x,y,fontAlign,line);
		delete line;		//必须使用此项,否则游戏开始2分钟后会自动退出
	}
	
	void	printfb(float x, float y, float w, float h, int fontAlign,  char *format, ...)
	{
		char*	pbuf, prevword, linestart;
		char	chr;
		int		i,lines=0;
		float	tx, ty, hh, ww;
		char*	pArg=cast(char *) (&format+ format.sizeof);

		vsprintf(toStringz(buffer), format, cast(void*)pArg);
		linestart=buffer.ptr;
		pbuf=buffer.ptr;
		prevword=null;

		for(;;)
		{
			i=0;
			while(pbuf[i] && pbuf[i]!=' ' && pbuf[i]!='\n') i++;

			chr=pbuf[i];
			pbuf[i]=0;
			ww=GetStringWidth(linestart[0..i]);
			pbuf[i]=chr;

			if(ww > w)
			{
				if(pbuf==linestart)
				{
					pbuf[i]='\n';
					linestart=&pbuf[i+1];
				}
				else
				{
					*prevword='\n';
					linestart=prevword+1;
				}

				lines++;
			}

			if(pbuf[i]=='\n')
			{
				prevword=&pbuf[i];
				linestart=&pbuf[i+1];
				pbuf=&pbuf[i+1];
				lines++;
				continue;
			}

			if(!pbuf[i]) {lines++;break;}

			prevword=&pbuf[i];
			pbuf=&pbuf[i+1];
		}
		
		tx=x;
		ty=y;
		hh=fHeight*fSpacing*fScale*lines;

		switch(fontAlign & HGETEXT_HORZMASK)
		{
			case HGETEXT_LEFT: break;
			case HGETEXT_RIGHT: tx+=w; break;
			case HGETEXT_CENTER: tx+=cast(int)(w/2); break;
			default :	break;
		}

		switch(fontAlign & HGETEXT_VERTMASK)
		{
			case HGETEXT_TOP: break;
			case HGETEXT_BOTTOM: ty+=h-hh; break;
			case HGETEXT_MIDDLE: ty+=cast(int)((h-hh)/2); break;
			default :	break;
		}

		Render(tx,ty,fontAlign,buffer);
	}





	void		SetColor(uint col)
	{
		dwCol=col;
		for(int i=0;i<256;i++) if(letters[i]) letters[i].SetColor(col);
	}


	
	void 		SetZ(float z)
	{
		fZ=z;
		for(int i=0;i<256;i++) if(letters[i]) letters[i].SetZ(z);
	}
	

	void 		SetBlendMode(int blend)
	{
		nBlend=blend;
		for(int i=0;i<256;i++) if(letters[i]) letters[i].SetBlendMode(blend);
	}

	
	void		SetScale(float scale) 			{fScale=scale;}
	void		SetRotation(float rot) 		{fRot=rot;}
	void		SetTracking(float tracking) 	{fTracking=tracking;}
	void		SetSpacing(float spacing) 		{fSpacing=spacing;}

	uint		GetColor()  				{return dwCol;}
	float		GetZ()  					{return fZ;}
	int			GetBlendMode()  			{return nBlend;}
	float		GetScale() 				{return fScale;}
	float		GetRotation()  			{return fRot;}
	float		GetTracking()  			{return fTracking;}
	float		GetSpacing()  			{return fSpacing;}

	hgeSprite	GetSprite(char chr)  		{return letters[cast(ubyte)chr]; }
	float		GetHeight()  				{ return fHeight; }

	

	float 		GetStringWidth( char[] string) 
	{
		int 	i;
		int 	j=0;
		float 	w=0;

		while(j<string.length && string[j]!='\n')
		{
			i=cast(ubyte)string[j];
			if(!letters[i]) i='?';
			if(letters[i]) w+=letters[i].GetWidth()+pre[i]+post[i]+fTracking;
			j++;
		}

		return w*fScale;
	}



private:

	static ifHge	hge;

	char[1024]		buffer;

	HTEXTURE		hTexture;
	hgeSprite[256]	letters;
	float[256]		pre;
	float[256]		post;
	float		fHeight;
	float		fScale;
	float		fRot;
	float		fTracking;
	float		fSpacing;

	uint		dwCol;
	float		fZ;
	int			nBlend;
}
